////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copyright (c) 2009 - 2010 RacoonStudios
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this
/// software and associated documentation files (the "Software"), to deal in the Software
/// without restriction, including without limitation the rights to use, copy, modify, merge,
/// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
/// to whom the Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all copies or
/// substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
/// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
/// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
/// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
/// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once
#ifndef referencecount_h__
#define referencecount_h__

#include "core/rtti.h"
#include "core/types.h"
#include "threading/interlocked.h"
#include "core/factory.h"

namespace Core
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \class	ReferenceCount
	///
	/// \brief	This is just a RefCounter with an integrated RTTI mechanism.
	///			At application shutdown we will check if there are some instance
	///			which were not correctly deleted and will list them within a log file.
	///
	/// \author	Khaos
	/// \date	02.01.2010
	////////////////////////////////////////////////////////////////////////////////////////////////////
	class ReferenceCount
	{
		RE_DeclareClass(Core::ReferenceCount);

	public:

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	ReferenceCount()
		///
		/// \brief	Default constructor. 
		///
		/// \author	Markus
		/// \date	12.02.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		ReferenceCount();




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	int GetRefCount() const
		///
		/// \brief	Gets the reference count. 
		///
		/// \author	Markus
		/// \date	12.02.2010
		///
		/// \return	The reference count. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		int GetRefCount() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void AddRef()
		///
		/// \brief	Adds  an instance.
		///
		/// \author	Markus
		/// \date	12.02.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void AddRef();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void Release()
		///
		/// \brief	Releases this instance. 
		///
		/// \author	Markus
		/// \date	12.02.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void Release();




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool IsInstOf(const Rtti & rtti) const
		///
		/// \brief	Determines if this class is an instance of the class specified through RTTI.
		///
		/// \author	Markus
		/// \date	12.02.2010
		///
		/// \param	[in]	rtti	The rtti. 
		///
		/// \return	True if this is an intance, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool IsInstOf(const Rtti & rtti) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool IsInstOf(const Helper::String & name) const
		///
		/// \brief	Determines if this class is an instance of the class specified through name.
		///
		/// \author	Markus
		/// \date	12.02.2010
		///
		/// \param	[in]	name	The name. 
		///
		/// \return	True if this is an instance, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool IsInstOf(const Helper::String & name) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool IsInstOf(const Helper::FCC & fcc) const
		///
		/// \brief	Determines if this class is an instance of the class specified through fcc.
		///
		/// \author	Markus
		/// \date	12.02.2010
		///
		/// \param	[in]	fcc	The fcc. 
		///
		/// \return	True if this is an instance, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool IsInstOf(const Helper::FCC & fcc) const;




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool IsA(const Rtti & rtti) const
		///
		/// \brief	Determines if this class inherites from the specified class through RTTI.
		///
		/// \author	Markus
		/// \date	12.02.2010
		///
		/// \param	[in]	rtti	The rtti. 
		///
		/// \return	True if this class is an inheritance of the class specified through the RTTI,
		///			otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool IsA(const Rtti & rtti) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool IsA(const Helper::String & name) const
		///
		/// \brief	Determines if this class inherites from the specified class through name.
		///
		/// \author	Markus
		/// \date	12.02.2010
		///
		/// \param	[in]	name	The name. 
		///
		/// \return	True if this class is an inheritance of the class specified through the name,
		///			otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool IsA(const Helper::String & name) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool IsA(const Helper::FCC & fcc) const
		///
		/// \brief	Determines if this class inherites from the specified class through fcc.
		///
		/// \author	Markus
		/// \date	12.02.2010
		///
		/// \param	[in]	fcc	The fcc. 
		///
		/// \return	True if this class is an inheritance of the class specified through the fcc,
		///			otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool IsA(const Helper::FCC & fcc) const;




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	const Helper::String & GetNameOfClass() const
		///
		/// \brief	Returns the name of this class. 
		///
		/// \author	Markus
		/// \date	12.02.2010
		///
		/// \return	The name of class. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		const Helper::String & GetNameOfClass() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	const Helper::FCC GetFCCOfClass() const
		///
		/// \brief	Returns the FCC of this class. 
		///
		/// \author	Markus
		/// \date	12.02.2010
		///
		/// \return	The FCC of this class. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		const Helper::FCC GetFCCOfClass() const;

	protected:

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual ~ReferenceCount()
		///
		/// \brief	Finaliser. 
		///
		/// \author	Markus
		/// \date	12.02.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual ~ReferenceCount();

	private:

		volatile int m_refCount;

	};

}

#endif // referencecount_h__